package com.neouton.crm.prm.service.impl;

import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.neouton.common.util.*;
import com.neouton.crm.dictionary.entity.DictionaryLookupItemVO;
import com.neouton.crm.dictionary.service.IDictionaryService;
import com.neouton.crm.entity.DynamicExcelData;
import com.neouton.crm.entity.SysUserEntity;
import com.neouton.crm.pm.entity.PurchaseOrderVO;
import com.neouton.crm.pm.mapper.PurchaseOrdeMapper;
import com.neouton.crm.prm.entity.ProjectReturnedMoneyVO;
import com.neouton.crm.prm.mapper.ProjectReturnedMoneyMapper;
import com.neouton.crm.prm.service.ProjectReturnedMoneyService;
import com.neouton.feginClient.FeginService;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static com.neouton.common.util.EasyExcelUtils.dynamicExport;
import static com.neouton.common.util.EasyExcelUtils.getDataList;

/**
 * 项目回款表
 *
 * @author
 * @date 2022-12-02 17:03:47
 * @Version 1.0
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ProjectReturnedMoneyServiceImpl implements ProjectReturnedMoneyService {
    @Resource
    private ProjectReturnedMoneyMapper projectReturnedMoneyMapper;
    @Resource
    private FeginService feginService;
    @Resource
    private IDictionaryService dictionaryService;
    @Value("${webSit.web}")
    private String webSitUrl;

    @Resource
    PurchaseOrdeMapper purchaseOrdeMapper;

    @Override
    public PageUtil<ProjectReturnedMoneyVO> queryReturnedMoneyList(IPage<ProjectReturnedMoneyVO> page, ProjectReturnedMoneyVO entity) {
        if (entity.getOrderByProp() != null) {
            entity.setOrderByProp(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(entity.getOrderByProp()));
        }
        IPage<ProjectReturnedMoneyVO> iPage = projectReturnedMoneyMapper.queryReturnedMoneyList(page, entity);
        List<ProjectReturnedMoneyVO> records = iPage.getRecords();
        if (records != null && !records.isEmpty()) {
            List<ProjectReturnedMoneyVO> voList = projectReturnedMoneyMapper.queryReturnedMoneyList(entity);
            for (ProjectReturnedMoneyVO item : records) {
                calcOverdueMoney(item);
            }
            for (ProjectReturnedMoneyVO item : voList) {
                calcOverdueMoney(item);
            }
            records = getTotalInfo(records, voList);
        }
        iPage.setRecords(records);
        return new PageUtil<>(iPage);
    }

    public List<ProjectReturnedMoneyVO> getTotalInfo(List<ProjectReturnedMoneyVO> pageList, List<ProjectReturnedMoneyVO> totalList) {
        var ref = new Object() {
            BigDecimal ZERO = new BigDecimal(BigInteger.ZERO);
            BigDecimal returnedMoney = new BigDecimal(BigInteger.ZERO);
            BigDecimal reservedMoney = new BigDecimal(BigInteger.ZERO);
            BigDecimal balanceMoney = new BigDecimal(BigInteger.ZERO);
            BigDecimal contractMoney = new BigDecimal(BigInteger.ZERO);
            BigDecimal returnMoney = new BigDecimal(BigInteger.ZERO);
            BigDecimal returnMoneyNow = new BigDecimal(BigInteger.ZERO);
            BigDecimal overdueMoney = new BigDecimal(BigInteger.ZERO);
            BigDecimal reservedMoneyAll = new BigDecimal(BigInteger.ZERO);
            BigDecimal returnedMoneyAll = new BigDecimal(BigInteger.ZERO);
            BigDecimal balanceMoneyAll = new BigDecimal(BigInteger.ZERO);
            BigDecimal contractMoneyAll = new BigDecimal(BigInteger.ZERO);
            BigDecimal returnMoneyAll = new BigDecimal(BigInteger.ZERO);
            BigDecimal returnMoneyNowAll = new BigDecimal(BigInteger.ZERO);
            BigDecimal overdueMoneyAll = new BigDecimal(BigInteger.ZERO);
        };
        Map<String, List<ProjectReturnedMoneyVO>> pageListMap = pageList.stream().collect(Collectors.groupingBy(ProjectReturnedMoneyVO::getContractNumber));
        pageListMap.forEach((name, list) -> {
            ref.contractMoney = ref.contractMoney.add(new BigDecimal(list.get(0).getContractMoney()));
            ref.reservedMoney = ref.reservedMoney.add(Objects.isNull(list.get(0).getReservedMoney()) ? ref.ZERO : new BigDecimal(list.get(0).getReservedMoney()));
            ref.returnedMoney = ref.returnedMoney.add(new BigDecimal(list.get(0).getReturnedMoney()));
            ref.balanceMoney = ref.balanceMoney.add(new BigDecimal(list.get(0).getBalanceMoney()));
        });
        Map<String, List<ProjectReturnedMoneyVO>> totalListMap = totalList.stream().collect(Collectors.groupingBy(ProjectReturnedMoneyVO::getContractNumber));
        totalListMap.forEach((name, list) -> {
            ref.contractMoneyAll = ref.contractMoneyAll.add(new BigDecimal(list.get(0).getContractMoney()));
            ref.reservedMoneyAll = ref.reservedMoneyAll.add(Objects.isNull(list.get(0).getReservedMoney()) ? ref.ZERO : new BigDecimal(list.get(0).getReservedMoney()));
            ref.returnedMoneyAll = ref.returnedMoneyAll.add(new BigDecimal(list.get(0).getReturnedMoney()));
            ref.balanceMoneyAll = ref.balanceMoneyAll.add(new BigDecimal(list.get(0).getBalanceMoney()));
        });
        pageList.forEach((item) -> {
            ref.returnMoney = ref.returnMoney.add(new BigDecimal(item.getReturnMoney()));
            ref.returnMoneyNow = ref.returnMoneyNow.add(Objects.isNull(item.getReturnMoney()) ? ref.ZERO : new BigDecimal(item.getReturnMoneyNow()));
            ref.overdueMoney = ref.overdueMoney.add((item.getOverdueMoney().equals("警告") || item.getOverdueMoney().equals("上报销售总监")) ? ref.ZERO : new BigDecimal(item.getOverdueMoney()));
        });
        totalList.forEach((item) -> {
            ref.returnMoneyAll = ref.returnMoneyAll.add(new BigDecimal(item.getReturnMoney()));
            ref.returnMoneyNowAll = ref.returnMoneyNowAll.add(Objects.isNull(item.getReturnMoney()) ? ref.ZERO : new BigDecimal(item.getReturnMoneyNow()));
            ref.overdueMoneyAll = ref.overdueMoneyAll.add((item.getOverdueMoney().equals("警告") || item.getOverdueMoney().equals("上报销售总监")) ? ref.ZERO : new BigDecimal(item.getOverdueMoney()));
        });
        pageList.get(0).setContractMoneyPage(ref.contractMoney.toString());
        pageList.get(0).setContractMoneyTotal(ref.contractMoneyAll.toString());
        pageList.get(0).setReservedMoneyPage(ref.reservedMoney.toString());
        pageList.get(0).setReservedMoneyTotal(ref.reservedMoneyAll.toString());
        pageList.get(0).setReturnedMoneyPage(ref.returnedMoney.toString());
        pageList.get(0).setReturnedMoneyTotal(ref.returnedMoneyAll.toString());
        pageList.get(0).setBalanceMoneyPage(ref.balanceMoney.toString());
        pageList.get(0).setBalanceMoneyTotal(ref.balanceMoneyAll.toString());
        pageList.get(0).setReturnMoneyPage(ref.returnMoney.toString());
        pageList.get(0).setReturnMoneyTotal(ref.returnMoneyAll.toString());
        pageList.get(0).setReturnMoneyNowPage(ref.returnMoneyNow.toString());
        pageList.get(0).setReturnMoneyNowTotal(ref.returnMoneyNowAll.toString());
        pageList.get(0).setOverdueMoneyPage(ref.overdueMoney.toString());
        pageList.get(0).setOverdueMoneyTotal(ref.overdueMoneyAll.toString());
        return pageList;
    }

    @Override
    public List<ProjectReturnedMoneyVO> queryReturnedMoneyList(ProjectReturnedMoneyVO entity) {
        if (entity.getOrderByProp() != null) {
            entity.setOrderByProp(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(entity.getOrderByProp()));
        }
        List<ProjectReturnedMoneyVO> records = projectReturnedMoneyMapper.queryReturnedMoneyList(entity);
        for (ProjectReturnedMoneyVO item : records) {
            calcOverdueMoney(item);
        }
        return records;
    }

    @Override
    public Map<String, Double> queryAllInfoByDate(ProjectReturnedMoneyVO entity) {
        List<ProjectReturnedMoneyVO> num = this.queryReturnedMoneyList(entity);
        Map<String, Double> map = new HashMap<>();
        if (num != null && num.size() > 0) {
            List<ProjectReturnedMoneyVO> array = new ArrayList<>();
            List<String> contractNumArr = new ArrayList<>();
            num.forEach((item) -> {
                if (contractNumArr.indexOf(item.getContractNumber()) < 0) {
                    array.add(item);
                    contractNumArr.add(item.getContractNumber());
                }
            });
            var ref = new Object() {
                double returnedMoneyAll = 0;
                double balanceMoneyAll = 0;
                double contractMoneyAll = 0;
                double notOverdueMoneyAll = 0;
                double overdueMoneyAll = 0;
            };
            array.forEach((item) -> {
                ref.contractMoneyAll += item.getContractMoney() == null ? 0 : Double.parseDouble(item.getContractMoney());
                ref.returnedMoneyAll += item.getReturnedMoney() == null ? 0 : Double.parseDouble(item.getReturnedMoney());
                ref.balanceMoneyAll += item.getBalanceMoney() == null ? 0 : Double.parseDouble(item.getBalanceMoney());
            });
            // 未到期
            List<ProjectReturnedMoneyVO> arrayx = num.stream().filter((res) -> res.getOverdueDays() <= 0).toList();
            arrayx.forEach((item) -> {
                ref.notOverdueMoneyAll += item.getReturnMoneyNow() == null ? Double.parseDouble(item.getReturnMoney()) : Double.parseDouble(item.getReturnMoney()) - Double.parseDouble(item.getReturnMoneyNow());
            });
            // 逾期
            List<ProjectReturnedMoneyVO> arrayy = num.stream().filter((res) -> res.getOverdueDays() > 0).toList();
            arrayy.forEach((item) -> {
                ref.overdueMoneyAll += item.getReturnMoneyNow() == null ? Double.parseDouble(item.getReturnMoney()) : Double.parseDouble(item.getReturnMoney()) - Double.parseDouble(item.getReturnMoneyNow());
            });
            map.put("contractMoneyAll", ref.contractMoneyAll);
            map.put("returnedMoneyAll", ref.returnedMoneyAll);
            map.put("balanceMoneyAll", ref.balanceMoneyAll);
            map.put("notOverdueMoneyAll", ref.notOverdueMoneyAll);
            map.put("overdueMoneyAll", ref.overdueMoneyAll);
        } else {
            map.put("contractMoneyAll", 0.00);
            map.put("returnedMoneyAll", 0.00);
            map.put("balanceMoneyAll", 0.00);
            map.put("notOverdueMoneyAll", 0.00);
            map.put("overdueMoneyAll", 0.00);
        }
        return map;
    }

    @Override
    public Map<String, Double> queryNowInfo(ProjectReturnedMoneyVO entity) {
        //获取当天0点时间
        long now = DateUtils.gettimeStemp(DateUtils.getDate1(), "");
        return this.queryInfoByDate(entity, now);
    }

    @Override
    public Map<String, Double> queryWeekInfo(ProjectReturnedMoneyVO entity) {
        //获取当天0点时间
        long now = DateUtils.gettimeStemp(DateUtils.getDate1(), "");
        long l = 86400000;
        long week = now - (l * 7);
        return this.queryInfoByDate(entity, week);
    }

    @Override
    public Map<String, Double> queryMonthInfo(ProjectReturnedMoneyVO entity) {
        //获取当天0点时间
        long now = DateUtils.gettimeStemp(DateUtils.getDate1(), "");
        long l = 86400000;
        long Month = now - (l * 30);
        return this.queryInfoByDate(entity, Month);
    }

    @Override
    public Map<String, Double> queryWeekStartInfo(ProjectReturnedMoneyVO entity) {
        String saturday = DateUtils.getLastWeekMonday(Calendar.SATURDAY);
        long now = DateUtils.gettimeStemp(saturday, "");
        long l = 86400000;
        long week = now - (l * 7);
        return this.queryInfoByDate(entity, week);
    }

    /**
     * 上周六0点
     *
     * @param entity
     * @return
     */
    @Override
    public Map<String, Double> queryWeekEndInfo(ProjectReturnedMoneyVO entity) {
        String saturday = DateUtils.getLastWeekMonday(Calendar.SATURDAY);
        long now = DateUtils.gettimeStemp(saturday, "");
        return this.queryInfoByDate(entity, now);
    }

    @Override
    public Map<String, Double> queryMonthStartInfo(ProjectReturnedMoneyVO entity) {
        String date = DateUtils.getLastMonthFirstDate();
        long now = DateUtils.gettimeStemp(date, "");
        return this.queryInfoByDate(entity, now);
    }

    @Override
    public Map<String, Double> queryMonthEndInfo(ProjectReturnedMoneyVO entity) {
        String date = DateUtils.getLastMonthEndDate();
        long now = DateUtils.gettimeStemp(date, "");
        return this.queryInfoByDate(entity, now);
    }

//    public Map<String, Double> queryInfoByDate(ProjectReturnedMoneyVO entity,long date) {
//        List<ProjectReturnedMoneyVO> num = this.queryAllInfo(entity);
//        Map<String, Double> map = new HashMap<>();
//        if (num != null && num.size() > 0) {
//            List<ProjectReturnedMoneyVO> array = new ArrayList<>();
//            List<String> contractNumArr = new ArrayList<>();
//            num.forEach((item) -> {
//                if (contractNumArr.indexOf(item.getContractNumber()) < 0) {
//                    array.add(item);
//                    contractNumArr.add(item.getContractNumber());
//                }
//            });
//            var ref = new Object() {
//                double returnedMoneyAll = 0;
//                double balanceMoneyAll = 0;
//                double contractMoneyAll = 0;
//                double notOverdueMoneyAll = 0;
//                double overdueMoneyAll = 0;
//            };
//            array.forEach((item) -> {
//                //合同总金额     合同日期小于日期
//                if (item.getContractDate().getTime() < date) {
//                    ref.contractMoneyAll += item.getContractMoney() == null ? 0 : Double.parseDouble(item.getContractMoney());
//                }
//                //未回总金额     逾期+未到期
////                ref.balanceMoneyAll += item.getBalanceMoney() == null ? 0 : Double.parseDouble(item.getBalanceMoney());
//            });
//            //已回总金额     实际回款日期小于日期
//            List<ProjectReturnedMoneyVO> arrays = num.stream().filter((res) -> (res.getReturnedMoneyDate() != null && res.getReturnedMoneyDate().getTime() < date)).collect(Collectors.toList());
//            List<ProjectReturnedMoneyVO> arraysR = new ArrayList<>();
//            List<String> contractNumArrR = new ArrayList<>();
//            //按合同分组
//            arrays.forEach((item) -> {
//                if (contractNumArrR.indexOf(item.getContractNumber()) < 0) {
//                    arraysR.add(item);
//                    contractNumArrR.add(item.getContractNumber());
//                }
//            });
//            arraysR.forEach((item) -> {
//                ref.returnedMoneyAll += item.getReturnedMoney() == null ? 0 : Double.parseDouble(item.getReturnedMoney());
//            });
//            // 未到期      计划回款日期大于日期
//            List<ProjectReturnedMoneyVO> arrayx = num.stream().filter((res) -> res.getReturnedMoneyPlanDate().getTime() > date).collect(Collectors.toList());
//            arrayx.forEach((item) -> {
//                ref.notOverdueMoneyAll += item.getReturnMoney() == null ? 0 : Double.parseDouble(item.getReturnMoney());
//            });
//            // 逾期       计划回款日期小于日期 且实际回款金额为0 一直未回
//            List<ProjectReturnedMoneyVO> arrayy = num.stream().filter((res) -> res.getReturnedMoneyPlanDate().getTime() < date && Double.parseDouble(res.getReturnMoneyNow()) == 0.0).collect(Collectors.toList());
//            arrayy.forEach((item) -> {
//                ref.overdueMoneyAll += item.getReturnMoney() == null ? 0 : Double.parseDouble(item.getReturnMoney());
//            });
//            //逾期        计划回款日期小于日期  且实际回款日期大于日期 本期才回的部分
//            List<ProjectReturnedMoneyVO> arrayz = num.stream().filter((res) -> res.getReturnedMoneyPlanDate().getTime() < date && (res.getReturnedMoneyDate() != null && res.getReturnedMoneyDate().getTime() > date)).collect(Collectors.toList());
//            arrayz.forEach((item) -> {
//                ref.overdueMoneyAll += item.getReturnMoney() == null ? 0 : Double.parseDouble(item.getReturnMoney());
//            });
//            map.put("contractMoneyAll",new BigDecimal(ref.contractMoneyAll / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
//            map.put("returnedMoneyAll",new BigDecimal(ref.returnedMoneyAll / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
//            map.put("balanceMoneyAll",new BigDecimal((ref.contractMoneyAll - ref.returnedMoneyAll) / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
//            map.put("notOverdueMoneyAll",new BigDecimal(ref.notOverdueMoneyAll / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
//            map.put("overdueMoneyAll",new BigDecimal(ref.overdueMoneyAll / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
//        } else {
//            map.put("contractMoneyAll",0.00);
//            map.put("returnedMoneyAll",0.00);
//            map.put("balanceMoneyAll",0.00);
//            map.put("notOverdueMoneyAll",0.00);
//            map.put("overdueMoneyAll",0.00);
//        }
//        return map;
//    }

    public Map<String, Double> queryInfoByDate(ProjectReturnedMoneyVO entity, long date) {
        List<ProjectReturnedMoneyVO> num = this.queryReturnedMoneyList(entity);
        Map<String, Double> map = new HashMap<>();
        if (num != null && !num.isEmpty()) {
            List<ProjectReturnedMoneyVO> array = new ArrayList<>();
            List<String> contractNumArr = new ArrayList<>();
            num.forEach((item) -> {
                if (!contractNumArr.contains(item.getContractNumber())) {
                    array.add(item);
                    contractNumArr.add(item.getContractNumber());
                }
            });
            var ref = new Object() {
                double returnedMoneyAll = 0;
                double balanceMoneyAll = 0;
                double contractMoneyAll = 0;
                double notOverdueMoneyAll = 0;
                double overdueMoneyAll = 0;
            };
            array.forEach((item) -> {
                //合同总金额     合同日期小于日期
                if (item.getContractDate().getTime() <= date) {
                    ref.contractMoneyAll += item.getContractMoney() == null ? 0 : Double.parseDouble(item.getContractMoney());
                }
            });
            //已回总金额     实际回款日期小于日期  且合同日期小于日期
            List<ProjectReturnedMoneyVO> arrays = num.stream().filter((res) -> (res.getReturnedMoneyDate() != null && res.getReturnedMoneyDate().getTime() <= date && res.getContractDate().getTime() <= date)).toList();
            arrays.forEach((item) -> {
                ref.returnedMoneyAll += item.getReturnedMoney() == null ? 0 : Double.parseDouble(item.getReturnMoneyNow());
            });
            // 未到期      计划回款日期大于日期  且合同日期小于日期
            List<ProjectReturnedMoneyVO> arrayx = num.stream().filter((res) -> (res.getReturnedMoneyPlanDate() != null && res.getReturnedMoneyPlanDate().getTime() >= date && res.getContractDate().getTime() <= date)).toList();
            arrayx.forEach((item) -> {
                //实际回在日期后回    实际不等于计划金额的（实际回款日期大于日期）
                if (item.getReturnedMoneyDate() != null && item.getReturnedMoneyDate().getTime() > date) {
                    ref.notOverdueMoneyAll += Double.parseDouble(item.getReturnMoney());
                } else {
                    //提前还   还完0；未还完为剩余的
                    ref.notOverdueMoneyAll += item.getReturnMoneyNow().equals(item.getReturnMoney()) ? 0 : (Double.parseDouble(item.getReturnMoney()) - Double.parseDouble(item.getReturnMoneyNow()));
                }
            });
            // 逾期       计划回款日期小于日期 且(实际回款金额小于计划 一直未回 or 实际回款日期大于日期 本期才回的部分) 且合同日期小于日期    实际=计划时，表示逾期但回了（暂不能解决部分回情况）
            List<ProjectReturnedMoneyVO> arrayy = num.stream().filter((res) -> res.getReturnedMoneyPlanDate() != null && res.getReturnedMoneyPlanDate().getTime() < date && (Double.parseDouble(res.getReturnMoneyNow()) < Double.parseDouble(res.getReturnMoney()) || (res.getReturnedMoneyDate() != null && res.getReturnedMoneyDate().getTime() > date)) && res.getContractDate().getTime() <= date).toList();
            arrayy.forEach((item) -> {
                //实际回在日期后回
                if (item.getReturnedMoneyDate() != null && item.getReturnedMoneyDate().getTime() > date) {
                    ref.overdueMoneyAll += Double.parseDouble(item.getReturnMoney());
                } else {
                    ref.overdueMoneyAll += item.getReturnMoneyNow().equals(item.getReturnMoney()) ? Double.parseDouble(item.getReturnMoney()) : (Double.parseDouble(item.getReturnMoney()) - Double.parseDouble(item.getReturnMoneyNow()));
                }
            });
            map.put("contractMoneyAll", BigDecimal.valueOf(ref.contractMoneyAll / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
            map.put("returnedMoneyAll", BigDecimal.valueOf(ref.returnedMoneyAll / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
            map.put("balanceMoneyAll", BigDecimal.valueOf((ref.notOverdueMoneyAll + ref.overdueMoneyAll) / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
            map.put("notOverdueMoneyAll", BigDecimal.valueOf(ref.notOverdueMoneyAll / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
            map.put("overdueMoneyAll", BigDecimal.valueOf(ref.overdueMoneyAll / 10000).setScale(2, RoundingMode.HALF_UP).doubleValue());
        } else {
            map.put("contractMoneyAll", 0.00);
            map.put("returnedMoneyAll", 0.00);
            map.put("balanceMoneyAll", 0.00);
            map.put("notOverdueMoneyAll", 0.00);
            map.put("overdueMoneyAll", 0.00);
        }
        return map;
    }

    public ProjectReturnedMoneyVO calcOverdueMoney(ProjectReturnedMoneyVO entity) {
        //不是逾期的
        if (!entity.getProjectState().equals(2)) {
            entity.setOverdueMoney("0.00");
            return entity;
        } else {
            if (entity.getOverdueDays() == null) {
                entity.setOverdueMoney("0.00");
                return entity;
            }
            if (entity.getOverdueDays() <= 30) {
                entity.setOverdueMoney("0.00");
            }
            if (entity.getOverdueDays() > 30 && entity.getOverdueDays() <= 90) {
                entity.setOverdueMoney("警告");
            }
            if (entity.getOverdueDays() > 90 && entity.getOverdueDays() <= 180) {
                String returnMoney = entity.getReturnMoney();
                double i = Double.parseDouble(returnMoney);
                BigDecimal bigDecimal = BigDecimal.valueOf(i * 0.01);
                bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
                entity.setOverdueMoney(bigDecimal.toString());
            }
            if (entity.getOverdueDays() > 180 && entity.getOverdueDays() <= 360) {
                String returnMoney = entity.getReturnMoney();
                double i = Double.parseDouble(returnMoney);
                BigDecimal bigDecimal = BigDecimal.valueOf(i * 0.015);
                bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
                entity.setOverdueMoney(bigDecimal.toString());
            }
            if (entity.getOverdueDays() > 360) {
                entity.setOverdueMoney("上报销售总监");
            }
            return entity;
        }
    }

    @Override
    public void saveProjectReturnedMoney(ProjectReturnedMoneyVO entity) {
        projectReturnedMoneyMapper.insert(entity);
        //同步更新合同总额
        ProjectReturnedMoneyVO moneyVO = new ProjectReturnedMoneyVO();
        moneyVO.setContractNumber(entity.getContractNumber());
        moneyVO.setContractMoney(entity.getContractMoney());
        moneyVO.setReservedMoney(entity.getReservedMoney());
        moneyVO.setLastUpdateBy(AuthUtils.getUserId());
        moneyVO.setLastUpdateDate(new Timestamp(System.currentTimeMillis()));
        projectReturnedMoneyMapper.updateReturnedMoney(moneyVO);
        ProjectReturnedMoneyVO record = projectReturnedMoneyMapper.selectByPrimaryKey(entity.getBmpId().longValue());
        if (record.getProjectState() == 2 && (record.getFlag() == 0 || record.getFlag() == null)) {
            CompletableFuture.runAsync(() -> NoticUtils.pushNotics(record.getBmpId(), new Timestamp(System.currentTimeMillis()), record.getReturnedPrincipal(), 0, 36, record.getReturnedPrincipal(), null));
            projectReturnedMoneyMapper.updateFlagById(new ArrayList<>(record.getBmpId()));
        }
    }

    @Override
    public void updateProjectReturnedMoneyById(ProjectReturnedMoneyVO entity) {
        ProjectReturnedMoneyVO recordVO = projectReturnedMoneyMapper.selectByPrimaryKey(entity.getBmpId().longValue());
        projectReturnedMoneyMapper.updateByPrimaryKeySelective(entity);
//        //同步更新合同总额
//        ProjectReturnedMoneyVO moneyVO = new ProjectReturnedMoneyVO();
//        moneyVO.setProjectTheme(entity.getProjectTheme());
//        moneyVO.setClientName(entity.getClientName());
//        moneyVO.setProjectPrincipal(entity.getProjectPrincipal());
//        moneyVO.setProjectAffiliation(entity.getProjectAffiliation());
//        moneyVO.setContractDate(entity.getContractDate());
//        moneyVO.setContractNumber(entity.getContractNumber());
//        moneyVO.setReservedMoney(entity.getReservedMoney());
//        moneyVO.setContractMoney(entity.getContractMoney());
//        projectReturnedMoneyMapper.updateReturnedMoney(moneyVO);
        ProjectReturnedMoneyVO record = projectReturnedMoneyMapper.selectByPrimaryKey(entity.getBmpId().longValue());
        if (record.getProjectState() == 2 && (record.getFlag() == 0 || record.getFlag() == null)) {
            //原负责人变更，且逾期时
            if (!record.getProjectPrincipal().equals(recordVO.getProjectPrincipal()) && recordVO.getFlag() == 1) {
                CompletableFuture.runAsync(() -> NoticUtils.pushNotics(recordVO.getBmpId(), new Timestamp(System.currentTimeMillis()), recordVO.getReturnedPrincipal(), 1, 36, recordVO.getReturnedPrincipal(), null));
            }
            //发送消息提醒
            CompletableFuture.runAsync(() -> NoticUtils.pushNotics(record.getBmpId(), new Timestamp(System.currentTimeMillis()), record.getReturnedPrincipal(), 0, 36, record.getReturnedPrincipal(), null));
            projectReturnedMoneyMapper.updateFlagById(new ArrayList<>(record.getBmpId()));
        }
        if (record.getFlag() == 1 && record.getProjectState() != 2) {
            //取消消息提醒
            CompletableFuture.runAsync(() -> NoticUtils.pushNotics(record.getBmpId(), new Timestamp(System.currentTimeMillis()), record.getReturnedPrincipal(), 1, 36, record.getReturnedPrincipal(), null));
            record.setFlag(0);
            projectReturnedMoneyMapper.updateFlagByPrimaryKey(record.getBmpId());
        }
    }

    @Override
    public void deleteprojectReturnedMoneyById(Integer id) {
        projectReturnedMoneyMapper.deleteByPrimaryKey(Long.valueOf(id));
    }

    @Override
    public ProjectReturnedMoneyVO getDetailInfo(Integer id) {
        return calcOverdueMoney(projectReturnedMoneyMapper.selectByPrimaryKey(Long.valueOf(id)));
    }

    @Override
    public List<Integer> queryPeriodState(String contractNumber) {
        List<ProjectReturnedMoneyVO> periodStateVOS = projectReturnedMoneyMapper.queryInfoOfReturnedMoney(contractNumber);
        return periodStateVOS.stream().map(ProjectReturnedMoneyVO::getReturnedMoneyPeriodState).collect(Collectors.toList());
    }

    @Override
    public Boolean verify(ProjectReturnedMoneyVO entity) {
        List<ProjectReturnedMoneyVO> list = projectReturnedMoneyMapper.queryInfoOfReturnedMoney(entity.getContractNumber());
        if (list != null && !list.isEmpty()) {
            double plan = 0.00;
            for (ProjectReturnedMoneyVO returnedMoneyVO : list) {
                plan += Double.parseDouble(returnedMoneyVO.getReturnMoney());
            }
            plan += Double.parseDouble(entity.getReturnMoney());
            double contractNumber = Double.parseDouble(list.get(0).getContractMoney());
            if (plan > contractNumber) {
                return true;
            }
        }
        return false;
    }

    @Override
    public ProjectReturnedMoneyVO queryInfoByContractNumber(String contractNumber) {
        List<ProjectReturnedMoneyVO> periodStateVOS = projectReturnedMoneyMapper.queryInfoByContractNumber(contractNumber);
        return (periodStateVOS != null && !periodStateVOS.isEmpty()) ? periodStateVOS.get(0) : new ProjectReturnedMoneyVO();
    }

//    @Override
//    public void downExcel(HttpServletResponse response, ProjectReturnedMoneyVO entity, String token) throws Exception {
//        List<ProjectReturnedMoneyVO> varOList = projectReturnedMoneyMapper.queryReturnedMoneyList(entity);
//        for (ProjectReturnedMoneyVO item : varOList) {
//            calcOverdueMoney(item);
//        }
//        ExcelData data = new ExcelData();
//        data.setName("回款明细表");
//        List<String> titles = new ArrayList<>();
//        titles.add("合同单号");
//        titles.add("项目名称");
//        titles.add("客户名称");
//        titles.add("负责人");
//        titles.add("回款跟踪");
//        titles.add("项目归属");
//        titles.add("合同日期");
//        titles.add("合同总金额");
//        titles.add("预留利润");
//        titles.add("已回款金额");
//        titles.add("余款总金额");
//        titles.add("当期状态");
//        titles.add("回款期次");
//        titles.add("当期计划回款");
//        titles.add("当期实际回款");
//        titles.add("计划回款日期");
//        titles.add("实际回款日期");
//        titles.add("开票状态");
//        titles.add("逾期天数");
//        titles.add("逾期罚息");
//        titles.add("回款进展");
////        titles.add("创建人");
////        titles.add("创建时间");
////        titles.add("更新人");
////        titles.add("更新时间");
//        data.setTitles(titles);
//        List<List<Object>> varList = new ArrayList();
//        List<String> statesList = new ArrayList<>();
//        statesList.add("projectState");
//        statesList.add("returnedMoneyPeriodState");
//        statesList.add("invoiceState");
//        JSONObject jsonObject = feginService.queryDictionaryLookupInfo("pms", statesList);
//        JSONObject userObject = feginService.getUserInfo(token);
//        for (int i = 0; i < varOList.size(); i++) {
//            List<Object> prm = new ArrayList();
//            prm.add(varOList.get(i).getContractNumber());
//            prm.add(varOList.get(i).getProjectTheme());
//            prm.add(varOList.get(i).getClientName());
//            prm.add(getUserNameById(userObject).get(String.valueOf(varOList.get(i).getProjectPrincipal())));
//            prm.add(getUserNameById(userObject).get(String.valueOf(varOList.get(i).getReturnedPrincipal())));
//            prm.add(varOList.get(i).getProjectAffiliation());
//            prm.add(ExcelUtils.exchangeSystemTimeToString(varOList.get(i).getContractDate()));
////            prm.add(varOList.get(i).getContractMoney());
////            prm.add(varOList.get(i).getReservedMoney() == null ? "" : varOList.get(i).getReservedMoney());
////            prm.add(varOList.get(i).getReturnedMoney());
////            prm.add(varOList.get(i).getBalanceMoney());
//            prm.add(new DecimalFormat("0.00").format(Double.parseDouble(varOList.get(i).getContractMoney())));
//            prm.add(new DecimalFormat("0.00").format(Double.parseDouble(varOList.get(i).getReservedMoney())));
//            prm.add(new DecimalFormat("0.00").format(Double.parseDouble(varOList.get(i).getReturnedMoney())));
//            prm.add(new DecimalFormat("0.00").format(Double.parseDouble(varOList.get(i).getBalanceMoney())));
//            prm.add(getDictionaryNameByCode("projectState", jsonObject).get(String.valueOf(varOList.get(i).getProjectState())));
//            prm.add(getDictionaryNameByCode("returnedMoneyPeriodState", jsonObject).get(String.valueOf(varOList.get(i).getReturnedMoneyPeriodState())));
////            prm.add(varOList.get(i).getReturnMoney());
////            prm.add(varOList.get(i).getReturnMoneyNow());
//            prm.add(new DecimalFormat("0.00").format(Double.parseDouble(varOList.get(i).getReturnMoney())));
//            prm.add(new DecimalFormat("0.00").format(Double.parseDouble(varOList.get(i).getReturnMoneyNow())));
//            prm.add(ExcelUtils.exchangeSystemTimeToString(varOList.get(i).getReturnedMoneyPlanDate()));
//            prm.add(ExcelUtils.exchangeSystemTimeToString(varOList.get(i).getReturnedMoneyDate()));
//            prm.add(getDictionaryNameByCode("invoiceState", jsonObject).get(String.valueOf(varOList.get(i).getInvoiceState())));
//            prm.add(String.valueOf(varOList.get(i).getOverdueDays()));
//            prm.add(varOList.get(i).getOverdueMoney());
//            prm.add(varOList.get(i).getProgressInfo());
////            prm.add(getUserMap().get(varOList.get(i).getCreatedBy()));
////            prm.add(ExcelUtils.exchangeSystemTimeToString(varOList.get(i).getCreationDate()));
////            prm.add(getUserMap().get(varOList.get(i).getLastUpdateBy()));
////            prm.add(ExcelUtils.exchangeSystemTimeToString(varOList.get(i).getLastUpdateDate()));
//            varList.add(prm);
//        }
//        data.setRows(varList);
//        try {
//            ExcelUtils.exportExcel(response, "回款信息文件.xlsx", data);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }

    /**
     * 导出
     *
     * @param response
     * @param entity
     * @param token
     * @throws Exception
     */
    @Override
    public void downExcel(HttpServletResponse response, ProjectReturnedMoneyVO entity, String token) throws Exception {
        List<ProjectReturnedMoneyVO> list = projectReturnedMoneyMapper.queryReturnedMoneyList(entity);
        for (ProjectReturnedMoneyVO item : list) {
            calcOverdueMoney(item);
        }
        List<String> statesList = new ArrayList<>();
        statesList.add("projectState");
        statesList.add("returnedMoneyPeriodState");
        statesList.add("invoiceState");
        JSONObject userObject = feginService.getUserInfo(token);
        JSONObject jsonObject = feginService.queryDictionaryLookupInfo("pms", statesList);
        List<String> classfiedCode = new ArrayList<>();
        classfiedCode.add("projectType");
        Map<String, List<DictionaryLookupItemVO>> listMap = dictionaryService.queryDictionaryLookupInfo(1, classfiedCode);
        for (int i = 0; i < list.size(); i++) {
            ProjectReturnedMoneyVO prmVO = list.get(i);
            prmVO.setProjectReturnedMoneyId(i + 1);
            prmVO.setProjectAffiliationName((String) getCRMDictionaryNameByCode("projectType", listMap).get(prmVO.getProjectAffiliation() + ""));
            prmVO.setProjectPrincipals((String) getUserNameById(userObject).get(prmVO.getProjectPrincipal()));
            prmVO.setReturnedPrincipals((String) getUserNameById(userObject).get(prmVO.getReturnedPrincipal()));
            prmVO.setProjectStates((String) getDictionaryNameByCode("projectState", jsonObject).get(prmVO.getProjectState() + ""));
            prmVO.setReturnedMoneyPeriodStates((String) getDictionaryNameByCode("returnedMoneyPeriodState", jsonObject).get(prmVO.getReturnedMoneyPeriodState() + ""));
            prmVO.setInvoiceStates((String) getDictionaryNameByCode("invoiceState", jsonObject).get(prmVO.getInvoiceState() + ""));
            prmVO.setContractMoney(new DecimalFormat("0.00").format(Double.parseDouble(prmVO.getContractMoney())));
            prmVO.setReservedMoney(new DecimalFormat("0.00").format(Double.parseDouble(prmVO.getReservedMoney())));
            prmVO.setReturnedMoney(new DecimalFormat("0.00").format(Double.parseDouble(prmVO.getReturnedMoney())));
            prmVO.setBalanceMoney(new DecimalFormat("0.00").format(Double.parseDouble(prmVO.getBalanceMoney())));
            prmVO.setReturnMoney(new DecimalFormat("0.00").format(Double.parseDouble(prmVO.getReturnMoney())));
            prmVO.setReturnMoneyNow(new DecimalFormat("0.00").format(Double.parseDouble(prmVO.getReturnMoneyNow())));
        }
        //获取yml模板位置
//        YamlPropertiesFactoryBean factoryBean = new YamlPropertiesFactoryBean();
//        String path = "application.yml";
//        factoryBean.setResources(new ClassPathResource(path));
//        Properties properties = factoryBean.getObject();
//        String templatePath = String.valueOf(properties.get("report.returnedMoneyTemplate"));
        //依据根目录获取模板位置
//        TemplateExportParams params = new TemplateExportParams(templatePath);
//        Map<String, Object> map = new HashMap<>();
//        map.put("returnedMoney", list);
//        ReportUtils.exportExcel(params, map, "回款信息", response);
        this.exportReturnMoneyExcel(response, list);
    }

    /**
     * 定时邮件
     */
    @Override
    public void getScheduleTask() {
        //获取全部回款信息
        List<ProjectReturnedMoneyVO> returnedMoneyVOS = projectReturnedMoneyMapper.queryReturnedMoneyList(new ProjectReturnedMoneyVO());
        //过滤得到未回款和逾期天数大于-30的信息  1未到期notOverdueDays，2逾期overdueDays
        ArrayList<ProjectReturnedMoneyVO> notOverdueDays = new ArrayList<>();
        for (ProjectReturnedMoneyVO record : returnedMoneyVOS) {
            if (record != null && record.getProjectState() != null && record.getOverdueDays() != null && (record.getProjectState() == 1 || record.getProjectState() == 2) && record.getOverdueDays() >= -30 && record.getOverdueDays() < 1) {
                notOverdueDays.add(record);
            }
        }
        ArrayList<ProjectReturnedMoneyVO> overdueDays = new ArrayList<>();
        for (ProjectReturnedMoneyVO record : returnedMoneyVOS) {
            if (record != null && record.getProjectState() != null && record.getOverdueDays() != null && (record.getProjectState() == 1 || record.getProjectState() == 2) && record.getOverdueDays() > 0) {
                overdueDays.add(record);
            }
        }
        if (!notOverdueDays.isEmpty() || !overdueDays.isEmpty()) {
            //数据字典查询邮件抄送人
            List<String> statesList = new ArrayList<>();
            statesList.add("carbonCopyer");
            //回款期次状态 get(String.valueOf(varOList.get(i).getReturnedMoneyPeriodState()))
            statesList.add("returnedMoneyPeriodState");
            JSONObject jsonObject = feginService.queryDictionaryLookupInfo("pms", statesList);
            String carbonCopyer = (String) getDictionaryNameByCode("carbonCopyer", jsonObject).get("carbonCopyer");
            Map returnedMoneyPeriodState = getDictionaryNameByCode("returnedMoneyPeriodState", jsonObject);
            //获取负责人信息
            List<SysUserEntity> userInformation = feginService.queryAllEffectiveUsers().getResult();
            SysUserEntity principal = new SysUserEntity();
            for (ProjectReturnedMoneyVO record : notOverdueDays) {
                for (SysUserEntity user : userInformation) {
                    if (user.getUserId().equals(record.getProjectPrincipal())) {
                        principal = user;
                        break;
                    }
                }
                int i = -30;
                while (i < 0) {
                    if (i == record.getOverdueDays()) {
                        try {
                            String periodState = returnedMoneyPeriodState.get(String.valueOf(record.getReturnedMoneyPeriodState())).toString();
                            //发送邮件
                            String titel = "【系统通知】回款事项即将到期 - 流程单提醒通知";
                            String msg = "<div><p>"
                                    + "尊敬的" + principal.getLoginName() + "：</p></div>"
                                    + "<div><p style='text-indent: 2em'>您好，现有回款事项即将到期，请您关注！</p></div>"
                                    + "<div><p style='text-indent: 2em'>合同单号：" + record.getContractNumber() + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>项目名称：" + record.getProjectTheme() + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>客户名称：" + record.getClientName() + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>期次状态：" + periodState + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>计划回款：" + new BigDecimal(record.getReturnMoney()).setScale(2, RoundingMode.HALF_UP) + "元</p></div>"
                                    + "<div><p style='text-indent: 2em'>实际回款：" + new BigDecimal(record.getReturnMoneyNow()).setScale(2, RoundingMode.HALF_UP) + "元</p></div>"
                                    + "<div><p style='text-indent: 2em'>未回金额：" + (new BigDecimal(record.getReturnMoney()).subtract(new BigDecimal(record.getReturnMoneyNow())).setScale(2, RoundingMode.HALF_UP)) + "元</p></div>"
                                    + "<div><p style='text-indent: 2em'>到期剩余天数：" + record.getOverdueDays() * -1 + "天</p></div>"
                                    + "<div><p style='text-indent: 2em'>计划回款日期：" + new SimpleDateFormat("yyyy-MM-dd").format(record.getReturnedMoneyPlanDate()) + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>系统查看路径：事项督办系统 - 公司回款督办 - 回款详情 "
                                    + "<a href='" + webSitUrl + "/?m=pms&p=returnedMoney&me=returnedMoneyInfo'>进入</a></p></div>"
                                    + "<div><p style='text-indent: 2em'>请及时处理以上事项！如已回款请登录公司回款督办系统更新信息。</p></div> "
                                    + "<div><p style='text-indent: 2em'>谢谢！</p></div>"
                                    + "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
                            SysUserEntity finalPrincipal = principal;
                            CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddresseeForData(finalPrincipal.getEmail(), carbonCopyer, titel, msg, ""));
                            Thread.sleep(2000);//使用这个方法可以使线程睡眠
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    } else {
                        i = i + 7;
                    }
                }
            }
            for (ProjectReturnedMoneyVO record : overdueDays) {
                for (SysUserEntity user : userInformation) {
                    if (user.getUserId().equals(record.getProjectPrincipal())) {
                        principal = user;
                        break;
                    }
                }
                int i = 1;
                while (i < 10000) {
                    if (i == record.getOverdueDays()) {
                        try {
                            String periodState = returnedMoneyPeriodState.get(String.valueOf(record.getReturnedMoneyPeriodState())).toString();
                            //发送邮件
                            String titel = "【系统通知】回款事项逾期 - 流程单提醒通知";
                            String msg = "<div><p>"
                                    + "尊敬的" + principal.getLoginName() + "：</p></div>"
                                    + "<div><p style='text-indent: 2em'>您好，现有回款事项已逾期，请您关注！</p></div>"
                                    + "<div><p style='text-indent: 2em'>合同单号：" + record.getContractNumber() + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>项目名称：" + record.getProjectTheme() + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>客户名称：" + record.getClientName() + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>期次状态：" + periodState + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>计划回款：" + new BigDecimal(record.getReturnMoney()).setScale(2, RoundingMode.HALF_UP) + "元</p></div>"
                                    + "<div><p style='text-indent: 2em'>实际回款：" + new BigDecimal(record.getReturnMoneyNow()).setScale(2, RoundingMode.HALF_UP) + "元</p></div>"
                                    + "<div><p style='text-indent: 2em'>逾期金额：" + (new BigDecimal(record.getReturnMoney()).subtract(new BigDecimal(record.getReturnMoneyNow())).setScale(2, RoundingMode.HALF_UP)) + "元</p></div>"
                                    + "<div><p style='text-indent: 2em'>逾期天数：" + record.getOverdueDays() + "天</p></div>"
                                    + "<div><p style='text-indent: 2em'>计划回款日期：" + new SimpleDateFormat("yyyy-MM-dd").format(record.getReturnedMoneyPlanDate()) + "</p></div>"
                                    + "<div><p style='text-indent: 2em'>系统查看路径：事项督办系统 - 公司回款督办 - 回款详情 "
                                    + "<a href='" + webSitUrl + "/?m=pms&p=returnedMoney&me=returnedMoneyInfo'>进入</a></p></div>"
                                    + "<div><p style='text-indent: 2em'>请及时处理以上事项！如已回款请登录公司回款督办系统更新信息。</p></div> "
                                    + "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
                            SysUserEntity finalPrincipal1 = principal;
                            CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddresseeForData(finalPrincipal1.getEmail(), carbonCopyer, titel, msg, ""));
                            Thread.sleep(2000);//使用这个方法可以使线程睡眠
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    } else {
                        i = i + 7;
                    }
                }
            }
            List<Integer> flagList = new ArrayList<>();
            for (ProjectReturnedMoneyVO record : returnedMoneyVOS) {
                //逾期且未发送
                if (record.getProjectState() == 2 && (record.getFlag() == 0 || record.getFlag() == null)) {
                    CompletableFuture.runAsync(() -> NoticUtils.pushNotics(record.getBmpId(), new Timestamp(System.currentTimeMillis()), record.getReturnedPrincipal(), 0, 36, record.getReturnedPrincipal(), null));
                    flagList.add(record.getBmpId());
                }
            }
            if (!flagList.isEmpty()) {
                projectReturnedMoneyMapper.updateFlagById(flagList);
            }
        }
    }

    @Override
    public void getScheduleMessage() {
        //获取全部回款信息
        List<ProjectReturnedMoneyVO> returnedMoneyVOS = projectReturnedMoneyMapper.queryReturnedMoneyList(new ProjectReturnedMoneyVO());
        List<Integer> flagList = new ArrayList<>();
        for (ProjectReturnedMoneyVO record : returnedMoneyVOS) {
            //逾期且未发送
            if (record.getProjectState() == 2 && (record.getFlag() == 0 || record.getFlag() == null)) {
                CompletableFuture.runAsync(() -> NoticUtils.pushNotics(record.getBmpId(), new Timestamp(System.currentTimeMillis()), record.getReturnedPrincipal(), 0, 36, record.getReturnedPrincipal(), null));
                flagList.add(record.getBmpId());
            }
        }
        if (!flagList.isEmpty()) {
            projectReturnedMoneyMapper.updateFlagById(flagList);
        }
    }

    @Override
    public Map<Integer, List<Double>> personData(ProjectReturnedMoneyVO entity) {
        List<ProjectReturnedMoneyVO> returnedMoneyVOS = queryReturnedMoneyList(entity);
        Map<Integer, List<ProjectReturnedMoneyVO>> userMap = returnedMoneyVOS.parallelStream()
                .collect(Collectors.groupingBy(ProjectReturnedMoneyVO::getProjectPrincipal));
        Set<Integer> keySet = userMap.keySet();
        Map<Integer, List<Double>> personData = new LinkedHashMap<>();
        for (Integer key : keySet) {
            List<Double> money = new ArrayList<>();
            List<ProjectReturnedMoneyVO> list = userMap.get(key);
            //按合同单号分
            Map<String, List<ProjectReturnedMoneyVO>> pactMap = list.parallelStream()

                    .collect(Collectors.groupingBy(ProjectReturnedMoneyVO::getContractNumber));
            Set<String> pactSet = pactMap.keySet();
            double contractMoneyAll = 0;
            double returnedMoneyAll = 0;
            double notOverdueMoneyAll = 0;
            double overdueMoneyAll = 0;
            for (String pact : pactSet) {
                List<ProjectReturnedMoneyVO> pactList = pactMap.get(pact);
                contractMoneyAll += Double.parseDouble(pactList.get(0).getContractMoney());
            }
            for (ProjectReturnedMoneyVO item : list) {
                String returnMoney = item.getReturnMoney();
                String returnMoneyNow = item.getReturnMoneyNow();
                returnedMoneyAll += Double.parseDouble(returnMoneyNow);
                if (item.getOverdueDays() <= 0) {
                    notOverdueMoneyAll += Double.parseDouble(returnMoney) - Double.parseDouble(returnMoneyNow);
                }
                if (item.getOverdueDays() > 0) {
                    overdueMoneyAll += Double.parseDouble(returnMoney) - Double.parseDouble(returnMoneyNow);
                }
            }
            money.add(contractMoneyAll);
            money.add(returnedMoneyAll);
            money.add(notOverdueMoneyAll);
            money.add(overdueMoneyAll);
            personData.put(key, money);
        }
//        List<Map.Entry<Integer, List<Double>>> list = new LinkedList<>(personData.entrySet());
//        list.sort((o1, o2) -> (o2.getValue().get(3)).compareTo(o1.getValue().get(3)));
//        Map<Integer, List<Double>> result = new LinkedHashMap<>();
//        for (Map.Entry<Integer, List<Double>> entry : list) {
//            result.put(entry.getKey(), entry.getValue());
//        }
        return personData;
    }

    private String getCoPerson(String str, String token) {
        if (StringUtils.isNotEmpty(str)) {
            String[] arr = str.split(",");
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < arr.length; i++) {
                if (i == arr.length - 1) {
                    result.append(getUserMap(token).get(Integer.valueOf(arr[i])));
                } else {
                    result.append(getUserMap(token).get(Integer.valueOf(arr[i])) + ",");
                }
            }
            return result.toString();
        } else {
            return str;
        }
    }

//    private SysUserEntity getUserInformation(List<SysUserEntity> userList,Integer userId) {
//        for (SysUserEntity user:userList) {
//            if (userId.equals(user.getUserId())) {
//                return user;
//            }
//        }
//        return null;
//    }


    private Map<Object, Object> getUserMap(String token) {
        Map<Object, Object> userMap = new HashMap<>();
        JSONObject userInfo = feginService.getUserInfo(token);
        List<HashMap<Object, Object>> userList = (ArrayList) userInfo.get("result");
        for (HashMap<Object, Object> user : userList) {
            if (user != null) {
                userMap.put(user.get("userId"), user.get("loginName"));
            }

        }
        return userMap;
    }

    private Map getDictionaryNameByCode(String itemCode, JSONObject jsonObject) {
        LinkedHashMap linkedHashMap = (LinkedHashMap) jsonObject.get("result");
        List<Map> dataDictionaryArray = (List) linkedHashMap.get(itemCode);
        Map<String, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (Map item : dataDictionaryArray) {
                map.put(item.get("itemCode").toString(), item.get("itemName").toString());
            }
        }
        return map;
    }

    //    private Map getUserNameById(JSONObject jsonObject) {
////        List<Map> userList = (List) jsonObject.get("result");
////        Map<String, String> map = new HashMap<>();
////        if (!CollectionUtils.isEmpty(userList)) {
////            for (Map item : userList) {
////                map.put(item.get("userId").toString(), item.get("loginName").toString());
////            }
////        }
////        return map;
////    }
    private Map getUserNameById(JSONObject jsonObject) {
        List<Map> dataDictionaryArray = (List) jsonObject.get("result");
        Map<Integer, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (Map item : dataDictionaryArray) {
                map.put((Integer) item.get("userId"), (String) item.get("loginName"));
            }
            return map;
        }
        return null;
    }

    private Map getCRMDictionaryNameByCode(String itemCode, Map listMap) {
        List<DictionaryLookupItemVO> dataDictionaryArray = (List) listMap.get(itemCode);
        Map<String, String> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(dataDictionaryArray)) {
            for (DictionaryLookupItemVO item : dataDictionaryArray) {
                map.put(item.getItemCode(), item.getItemName());
            }
            return map;
        }
        return null;
    }

    public void updateMessageFlagByList(List<ProjectReturnedMoneyVO> voList) {
        List<Integer> list1 = new ArrayList<>();//关闭
        List<Integer> list0 = new ArrayList<>();//发送
        for (ProjectReturnedMoneyVO recordVO : voList) {
            if (recordVO.getFlag() == 1) {//已发过消息的关闭消息
                CompletableFuture.runAsync(() -> NoticUtils.pushNotics(recordVO.getBmpId(), new Timestamp(System.currentTimeMillis()), recordVO.getReturnedPrincipal(), 1, 36, recordVO.getReturnedPrincipal(), null));
                list1.add(recordVO.getBmpId());
            }
            if (recordVO.getProjectState() == 2) {//逾期的发送提醒
                CompletableFuture.runAsync(() -> NoticUtils.pushNotics(recordVO.getBmpId(), new Timestamp(System.currentTimeMillis()), recordVO.getReturnedPrincipal(), 0, 36, recordVO.getReturnedPrincipal(), null));
                list0.add(recordVO.getBmpId());
            }
        }
        if (!list1.isEmpty()) {
            projectReturnedMoneyMapper.cancelFlagById(list1);
        }
        if (!list0.isEmpty()) {
            projectReturnedMoneyMapper.updateFlagById(list0);
        }
    }

    void exportReturnMoneyExcel(HttpServletResponse response, List<ProjectReturnedMoneyVO> list) throws Exception {
        List handleColMenu = Arrays.asList("projectTheme","contractNumber","contractName","clientName","projectPrincipal","projectAffiliation","contractDate","contractMoneyNum","reservedMoneyNum","returnedMoneyNum", "balanceMoneyNum", "returnedPrincipal");
        List<Map<String,Object>> tableConfigList = purchaseOrdeMapper.queryRefundShowTableConfig("pms", "returnedMoneyInfo");
        LinkedHashMap<String, DynamicExcelData> nameMap = new LinkedHashMap<>(0,1.6f,true);
        List<Integer> mergeColumnIndex = new ArrayList();
        for (int i = 0; i < tableConfigList.size(); i++) {
            Map item = tableConfigList.get(i);
            String name = String.valueOf(item.get("prop"));
            if (handleColMenu.indexOf(name) != -1) {
                mergeColumnIndex.add(i);
            }
            if (!"progressInfo".equals(name)) {  // 回款详情不导出
                if ("contractMoneyNum".equals(name)) {  // 合同总金额特殊处理，字段替换
                    name = "contractMoney";
                } else if ("returnedMoneyNum".equals(name)) {  // 合同已回总额特殊处理，字段替换
                    name = "returnedMoney";
                } else if ("balanceMoneyNum".equals(name)) {  // 合同未回总额特殊处理，字段替换
                    name = "balanceMoney";
                } else if ("returnMoneyNum".equals(name)) {  // 当期计划回款特殊处理，字段替换
                    name = "returnMoney";
                } else if ("returnMoneyNowNum".equals(name)) {  // 当期实际回款特殊处理，字段替换
                    name = "returnMoneyNow";
                } else if ("overdueMoneyNum".equals(name)) {  // 当期实际回款特殊处理，字段替换
                    name = "overdueMoney";
                } else if ("projectPrincipal".equals(name)) {  // 当期实际回款特殊处理，字段替换
                    name = "projectPrincipals";
                } else if ("returnedPrincipal".equals(name)) {  // 当期实际回款特殊处理，字段替换
                    name = "returnedPrincipals";
                } else if ("projectState".equals(name)) {  // 当期状态特殊处理，字段替换
                    name = "projectStates";
                } else if ("returnedMoneyPeriodState".equals(name)) {  // 回款期次特殊处理，字段替换
                    name = "returnedMoneyPeriodStates";
                } else if ("invoiceState".equals(name)) {  // 开票状态特殊处理，字段替换
                    name = "invoiceStates";
                } else if ("projectAffiliation".equals(name)) {  // 项目归属特殊处理，字段替换
                    name = "projectAffiliationName";
                } else if ("reservedMoneyNum".equals(name)) {  // 预留利润特殊处理，字段替换
                    name = "reservedMoney";
                }
                nameMap.put(name, new DynamicExcelData(String.valueOf(item.get("label")), null));
            }
        }
        List<Map<String, Object>> dataList = getDataList(list, Arrays.asList());
        dynamicExport(response,nameMap, dataList,"回款详情",  mergeColumnIndex.toArray(new Integer[mergeColumnIndex.size()]), true, "projectManageId");
    }
}
